package com.ruoyi.web.controller.system;

import java.util.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.ruoyi.system.service.ISysDeptService;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.handler.traffic.ChannelTrafficShapingHandler;
import io.netty.handler.traffic.TrafficCounter;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.harsh.common.NodeStatus;
import org.harsh.common.TransDetail;
import org.harsh.dispatch.CommVars;
import org.harsh.dispatch.Dispatcher;
import org.harsh.dispatch.NodeStatusCheckTask;
import org.harsh.transmission.common.GlobalTraffic;
import org.harsh.transmission.domain.TransTask;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.ShiroConstants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.utils.CookieUtils;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.shiro.service.SysPasswordService;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysMenuService;

/**
 * 首页 业务处理
 *
 * @author ruoyi
 */
@Controller
public class SysIndexController extends BaseController {
    @Autowired
    private ISysMenuService menuService;

    @Autowired
    private ISysConfigService configService;

    @Autowired
    private SysPasswordService passwordService;

    @Autowired
    private ISysDeptService sysDeptService;

    // 系统首页
    @GetMapping("/index")
    public String index(ModelMap mmap) {
        // 取身份信息
        SysUser user = getSysUser();
        // 根据用户id取出菜单
        List<SysMenu> menus = menuService.selectMenusByUser(user);
        mmap.put("menus", menus);
        mmap.put("user", user);
        mmap.put("sideTheme", configService.selectConfigByKey("sys.index.sideTheme"));
        mmap.put("skinName", configService.selectConfigByKey("sys.index.skinName"));
        Boolean footer = Convert.toBool(configService.selectConfigByKey("sys.index.footer"), true);
        Boolean tagsView = Convert.toBool(configService.selectConfigByKey("sys.index.tagsView"), true);
        mmap.put("footer", footer);
        mmap.put("tagsView", tagsView);
        mmap.put("mainClass", contentMainClass(footer, tagsView));
        mmap.put("copyrightYear", RuoYiConfig.getCopyrightYear());
        mmap.put("demoEnabled", RuoYiConfig.isDemoEnabled());
        mmap.put("isDefaultModifyPwd", initPasswordIsModify(user.getPwdUpdateDate()));
        mmap.put("isPasswordExpired", passwordIsExpiration(user.getPwdUpdateDate()));
        mmap.put("isMobile", ServletUtils.checkAgentIsMobile(ServletUtils.getRequest().getHeader("User-Agent")));

        // 菜单导航显示风格
        String menuStyle = configService.selectConfigByKey("sys.index.menuStyle");
        // 移动端，默认使左侧导航菜单，否则取默认配置
        String indexStyle = ServletUtils.checkAgentIsMobile(ServletUtils.getRequest().getHeader("User-Agent")) ? "index" : menuStyle;

        // 优先Cookie配置导航菜单
        Cookie[] cookies = ServletUtils.getRequest().getCookies();
        for (Cookie cookie : cookies) {
            if (StringUtils.isNotEmpty(cookie.getName()) && "nav-style".equalsIgnoreCase(cookie.getName())) {
                indexStyle = cookie.getValue();
                break;
            }
        }
        String webIndex = "topnav".equalsIgnoreCase(indexStyle) ? "index-topnav" : "index";
        return webIndex;
    }

    // 锁定屏幕
    @GetMapping("/lockscreen")
    public String lockscreen(ModelMap mmap) {
        mmap.put("user", getSysUser());
        ServletUtils.getSession().setAttribute(ShiroConstants.LOCK_SCREEN, true);
        return "lock";
    }

    // 解锁屏幕
    @PostMapping("/unlockscreen")
    @ResponseBody
    public AjaxResult unlockscreen(String password) {
        SysUser user = getSysUser();
        if (StringUtils.isNull(user)) {
            return AjaxResult.error("服务器超时，请重新登录");
        }
        if (passwordService.matches(user, password)) {
            ServletUtils.getSession().removeAttribute(ShiroConstants.LOCK_SCREEN);
            return AjaxResult.success();
        }
        return AjaxResult.error("密码不正确，请重新输入。");
    }

    // 切换主题
    @GetMapping("/system/switchSkin")
    public String switchSkin() {
        return "skin";
    }

    // 切换菜单
    @GetMapping("/system/menuStyle/{style}")
    public void menuStyle(@PathVariable String style, HttpServletResponse response) {
        CookieUtils.setCookie(response, "nav-style", style);
    }

    // 系统介绍
    @GetMapping("/system/main")
    public String main(ModelMap mmap) {
        mmap.put("version", RuoYiConfig.getVersion());
        return "main";
    }

    @Data
    @AllArgsConstructor
    class ChannelInfo {
        private String tcpChannelId;
        private long tcpWriteLimit;
        private long tcpReadLimit;
        private long tcpCheckInterval;
        private String kcpChannelId;
        private long kcpWriteLimit;
        private long kcpReadLimit;
        private long kcpCheckInterval;
    }

    @Data
    @AllArgsConstructor
    class CurrentTaskInfo {
        private long taskId;
        private int taskType;
        private int taskStatus;
        private long offset;
        private long recvOffset;
        private long totalSize;
        private DateTime startTime;

    }

    @GetMapping("/system/main_v1")
    public String mainVersion(ModelMap mmap) {
        TrafficCounter trafficCounter = GlobalTraffic.getInstance().trafficCounter();
        mmap.put("version", RuoYiConfig.getVersion());
        mmap.put("totalRead", trafficCounter.cumulativeReadBytes() >> 10);
        mmap.put("totalWritten", trafficCounter.cumulativeWrittenBytes()>> 10);
        mmap.put("lastCumuTime", DateUtil.date(trafficCounter.lastCumulativeTime()));
        mmap.put("currentRead", trafficCounter.currentReadBytes() >> 10);
        mmap.put("currentWritten", trafficCounter.currentWrittenBytes() >> 10);

        JSONArray array = JSONUtil.parseArray(NodeStatusCheckTask.nodeStatusMap.values());
//        System.out.println(array);
        mmap.put("nodeStatus", array);

        // 读取节点状态及数据情况
        Map<Long, ChannelInfo> nodeChannelInfo = new HashMap<>();
        for(long id : CommVars.nodeChannel.keySet()) {
            Channel channel = CommVars.nodeChannel.get(id);
            String channelId = channel.id().asLongText();
            channelId = channelId.split("-")[2];
            ChannelTrafficShapingHandler trafficShapingHandler = (ChannelTrafficShapingHandler) channel.pipeline().get("channelTraffic");
            long readLimit = 0;
            long writeLimit = 0;
            long checkInterval = 1;
            if(trafficShapingHandler != null) {
                readLimit = trafficShapingHandler.getReadLimit();
                writeLimit = trafficShapingHandler.getWriteLimit();
                checkInterval = trafficShapingHandler.getCheckInterval();
            }
            Channel kcpChannel = CommVars.nodeKcpChannel.get(id);
            String kcpChannelId = kcpChannel.id().asLongText();
            kcpChannelId = kcpChannelId.split("-")[2];
            ChannelTrafficShapingHandler kcpTrafficShapingHandler = (ChannelTrafficShapingHandler) kcpChannel.pipeline().get("channelTraffic");
            long kcpReadLimit = 0;
            long kcpWriteLimit = 0;
            long kcpCheckInterval = 1;
            if(kcpTrafficShapingHandler != null) {
                kcpReadLimit = kcpTrafficShapingHandler.getReadLimit();
                kcpWriteLimit = kcpTrafficShapingHandler.getWriteLimit();
                kcpCheckInterval = kcpTrafficShapingHandler.getCheckInterval();
            }
            ChannelInfo channelInfo = new ChannelInfo(channelId, writeLimit, readLimit, checkInterval, kcpChannelId, kcpWriteLimit, kcpReadLimit, kcpCheckInterval);
            nodeChannelInfo.put(id, channelInfo);
        }
        mmap.put("nodeChannel", nodeChannelInfo);

        List<CurrentTaskInfo> taskInfos = new ArrayList<>();
        for(TransDetail detail : CommVars.loadedTask.values()) {
            long sendPos = detail.getSendPos();
            DateTime startTime = detail.getStartTime();
            TransTask task = detail.getTransTask();
            long totalSize = detail.getTotalSize();
            long recvSize = task.getTaskOffset();
            CurrentTaskInfo taskInfo = new CurrentTaskInfo(
                    task.getTaskId(), task.getTaskType().intValue(), task.getTaskStatus().intValue(), sendPos, recvSize, totalSize, startTime );
            taskInfos.add(taskInfo);
        }
        mmap.put("taskInfos", taskInfos);

        return "main_v1";
    }


    // content-main class
    public String contentMainClass(Boolean footer, Boolean tagsView) {
        if (!footer && !tagsView) {
            return "tagsview-footer-hide";
        } else if (!footer) {
            return "footer-hide";
        } else if (!tagsView) {
            return "tagsview-hide";
        }
        return StringUtils.EMPTY;
    }

    // 检查初始密码是否提醒修改
    public boolean initPasswordIsModify(Date pwdUpdateDate) {
        Integer initPasswordModify = Convert.toInt(configService.selectConfigByKey("sys.account.initPasswordModify"));
        return initPasswordModify != null && initPasswordModify == 1 && pwdUpdateDate == null;
    }

    // 检查密码是否过期
    public boolean passwordIsExpiration(Date pwdUpdateDate) {
        Integer passwordValidateDays = Convert.toInt(configService.selectConfigByKey("sys.account.passwordValidateDays"));
        if (passwordValidateDays != null && passwordValidateDays > 0) {
            if (StringUtils.isNull(pwdUpdateDate)) {
                // 如果从未修改过初始密码，直接提醒过期
                return true;
            }
            Date nowDate = DateUtils.getNowDate();
            return DateUtils.differentDaysByMillisecond(nowDate, pwdUpdateDate) > passwordValidateDays;
        }
        return false;
    }
}
